package cn.b504.qpcr.config

import azure2java.qpcradapter.QpcrUtils
import cn.b504.qpcr.utils.OSUtils
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.scheduling.annotation.AsyncConfigurer
import org.springframework.scheduling.annotation.EnableAsync
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
import org.springframework.web.multipart.commons.CommonsMultipartResolver
import sun.security.action.GetPropertyAction
import java.io.File
import java.security.AccessController
import java.util.concurrent.Executor

@Configuration
open class ApplicationConfig {

  @Bean("multipartResolver")
  open fun commonsMultipartResolver(): CommonsMultipartResolver {
    val cmr = CommonsMultipartResolver()
    cmr.setDefaultEncoding(Charsets.UTF_8.toString())
    // 指定所上传文件的总大小，maxUploadSize限制不是针对单个文件，而是所有文件的容量之和
    cmr.setMaxUploadSize(100 * 1048576)    // 单位 b，1048576 b = 1Mb
    return cmr
  }

  @Bean
  open fun qpcrUtils(): QpcrUtils {
    val qpcr = QpcrUtils()
    qpcr.init()
    return qpcr
  }

  @Bean
  open fun idOfCPUHashCode(): String {
    return OSUtils.hash(OSUtils.getIdOfCPU())
  }

  @Bean
  open fun idOfCPUHashCodeHashCode(idOfCPUHashCode: String): String {
    return OSUtils.hash224(idOfCPUHashCode)
  }

  @Bean
  open fun tmpPath(): String {
    return File(AccessController.doPrivileged(GetPropertyAction("java.io.tmpdir"))).absolutePath
  }
}


@Configuration
@EnableAsync
open class TaskExecutorConfig : AsyncConfigurer {
  override fun getAsyncExecutor(): Executor {
    val threadPoolTaskExecutor = ThreadPoolTaskExecutor()
    /*  线程池核心线程数，核心线程会一直存活，即使没有任务需要处理。
     *  当线程数小于核心线程数时，即使现有的线程空闲，线程池也会优先创建新线程来处理任务，而不是直接交给现有的线程处理。
     *  核心线程在 allowCoreThreadTimeout 被设置为 true 时会超时退出，默认情况下不会退出。
     *  默认时是 1
     */
    // CPU 核心数 Runtime.getRuntime().availableProcessors();
    threadPoolTaskExecutor.corePoolSize = Runtime.getRuntime().availableProcessors() + 1

    /*  当线程数大于或等于核心线程，且任务队列已满时，线程池会创建新的线程，直到线程数量达到 maxPoolSize。
     *  如果线程数已等于 maxPoolSize，且任务队列已满，则已超出线程池的处理能力，线程池会拒绝处理任务而抛出异常。
     *  默认时是 Integer.MAX_VALUE
     */
    threadPoolTaskExecutor.maxPoolSize = Runtime.getRuntime().availableProcessors() + 1

    /*  任务队列容量。从 maxPoolSize 的描述上可以看出，任务队列的容量会影响到线程的变化，因此任务队列的长度也需要恰当的设置。
     *  默认时是 Integer.MAX_VALUE
     */
    // threadPoolTaskExecutor.setQueueCapacity(36);

    /*  keepAliveTime: 当线程空闲时间达到 keepAliveTime，该线程会退出，直到线程数量等于 corePoolSize。
     *  默认时是 60
     */
    // threadPoolTaskExecutor.setKeepAliveSeconds(10);

    /*  allowCoreThreadTimeout: 是否允许核心线程空闲退出。
     *  如果 allowCoreThreadTimeout 设置为 true，则所有线程均会退出直到线程数量为0。
     *  默认时是 false
     */
    // threadPoolTaskExecutor.setAllowCoreThreadTimeOut(true);

    threadPoolTaskExecutor.initialize()
    return threadPoolTaskExecutor
  }

  override fun getAsyncUncaughtExceptionHandler(): AsyncUncaughtExceptionHandler? {
    return null
  }
}
